

package com.gree.shyun.server.db.sqlite;



import com.gree.shyun.server.db.DbManager;
import com.gree.shyun.server.db.table.*;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.concurrent.ConcurrentHashMap;

public class ResultSetUtils {
    /**
     * 获取列名所在的位置
     * @param resultSet
     * @param idColumnName
     * @return
     * @throws SQLException
     */
    public static int getColumnIndex(ResultSet resultSet,String idColumnName) throws SQLException {
        int idIndex = 1;
        ResultSetMetaData metaData = resultSet.getMetaData();
        int count=metaData.getColumnCount();
        for(int i=1;i<=count;i++){
            if(idColumnName.equals(metaData.getColumnName(i))){
                idIndex = i;
                break;
            }
        }
        return idIndex;
    }

    /**
     *  获取列数
     * @param resultSet
     * @return
     * @throws SQLException
     */
    public static int getColumnCount(ResultSet resultSet) throws SQLException {
        ResultSetMetaData metaData = resultSet.getMetaData();
        return metaData.getColumnCount();
    }

    /**
     *  获取字段类型
     * @param resultSet
     * @param i
     * @return
     * @throws SQLException
     */
    public static int getColumnType(ResultSet resultSet,int i) throws SQLException {
        ResultSetMetaData metaData = resultSet.getMetaData();
        return metaData.getColumnType(i);
    }

    /**
     *  获取列名
     * @param resultSet
     * @param index
     * @return
     * @throws SQLException
     */
    public static String getColumnName(ResultSet resultSet,int index) throws SQLException {
        ResultSetMetaData metaData = resultSet.getMetaData();
        return metaData.getColumnName(index);
    }
    @SuppressWarnings("unchecked")
    public static <T> T getEntity(final DbManager db, final ResultSet resultSet, Class<T> entityType, long findCacheSequence) {
        if (db == null || resultSet == null) return null;

        EntityTempCache.setSeq(findCacheSequence);
        try {
            Table table = Table.get(db, entityType);
            Id id = table.id;
            String idColumnName = id.getColumnName();
            int idIndex = id.getIndex();
            if (idIndex < 0) {
                idIndex = getColumnIndex(resultSet,idColumnName);
            }
            Object idValue = id.getColumnConverter().getFieldValue(resultSet, idIndex);
            T entity = EntityTempCache.get(entityType, idValue);
            if (entity == null) {
                entity = entityType.newInstance();
                id.setValue2Entity(entity, resultSet, idIndex);
                EntityTempCache.put(entityType, idValue, entity);
            } else {
                return entity;
            }
            int columnCount = getColumnCount(resultSet);
            for (int i = 1; i <= columnCount; i++) {
                String columnName = getColumnName(resultSet,i);
                Column column = table.columnMap.get(columnName);
                if (column != null) {
                    column.setValue2Entity(entity, resultSet, i);
                }
            }

            // init finder
            for (Finder finder : table.finderMap.values()) {
                finder.setValue2Entity(entity, null, 0);
            }
            return entity;
        } catch (Throwable e) {
            e.printStackTrace();
        }

        return null;
    }

    public static DbModel getDbModel(final ResultSet resultSet) throws SQLException {
        DbModel result = null;
        if (resultSet != null) {
            result = new DbModel();
            int columnCount = getColumnCount(resultSet);
            for (int i = 1; i <= columnCount; i++) {
                result.add(getColumnName(resultSet,i), resultSet.getString(i));
            }
        }
        return result;
    }

    public static class FindCacheSequence {
        private FindCacheSequence() {
        }

        private static long seq = 0;
        private static final String FOREIGN_LAZY_LOADER_CLASS_NAME = ForeignLazyLoader.class.getName();
        private static final String FINDER_LAZY_LOADER_CLASS_NAME = FinderLazyLoader.class.getName();

        public static long getSeq() {
            String findMethodCaller = Thread.currentThread().getStackTrace()[4].getClassName();
            if (!findMethodCaller.equals(FOREIGN_LAZY_LOADER_CLASS_NAME) && !findMethodCaller.equals(FINDER_LAZY_LOADER_CLASS_NAME)) {
                ++seq;
            }
            return seq;
        }
    }

    private static class EntityTempCache {
        private EntityTempCache() {
        }

        private static final ConcurrentHashMap<String, Object> cache = new ConcurrentHashMap<String, Object>();

        private static long seq = 0;

        public static <T> void put(Class<T> entityType, Object idValue, Object entity) {
            cache.put(entityType.getName() + "#" + idValue, entity);
        }

        @SuppressWarnings("unchecked")
        public static <T> T get(Class<T> entityType, Object idValue) {
            return (T) cache.get(entityType.getName() + "#" + idValue);
        }

        public static void setSeq(long seq) {
            if (EntityTempCache.seq != seq) {
                cache.clear();
                EntityTempCache.seq = seq;
            }
        }
    }
}
